using System;
using System.Collections.Generic;
using Net;
using Net.AOI;
using Net.Common;
using Net.Entities;
using Net.Helper;
using Net.Share;
using Net.System;

namespace ActorSystem
{
#if ACTOR_SYSTEM_IN_MONO
    public abstract class ActorBase : UnityEngine.MonoBehaviour, IGridObject, IDisposable
#else
    public abstract class ActorBase : Component, IGridObject, IDisposable
#endif
    {
        public long Identity { get; set; }
        public virtual Vector3 Position { get => transform.Position; set => transform.Position = value; }
        [Net.Serialize.NonSerialized] public Grid Grid { get; set; }
        [Net.Serialize.NonSerialized] public bool MainRole { get; set; }
        [Net.Serialize.NonSerialized] public Scene Scene => Entity.World as Scene;
        private uint actorType;
        public uint ActorType
        {
            get
            {
                if (actorType == 0)
                    actorType = GetType().ToString().CRCU32();
                return actorType;
            }
        }
        public EntityTransform transform = new();

        [Net.Serialize.NonSerialized] public FastList<Operation> currOpers = new();//发给其他客户端
        [Net.Serialize.NonSerialized] public Operation[] tempOpers;
        [Net.Serialize.NonSerialized] public uint frame;

#if !SERVER
        [Net.Serialize.NonSerialized] public ActorView View { get; set; }
#endif

        public MyDictionary<byte, OperCommandDelegate> Commands { get; set; } = new();

        void IGridObject.OnInit() { }
        public virtual void OnEnter(IGridObject gridObject) { }
        public virtual void OnExit(IGridObject gridObject) { }
        public virtual void OnEnterGrid(Grid enterGrid) { }
        public virtual void OnLeaveGrid(Grid leaveGrid) { }
        public virtual void OnOperation(in Operation opt)
        {
            if (Commands.TryGetValue(opt.cmd, out var action))
                action(opt);
            else
                AddOperation(opt);
        }
        public virtual void AddOperation(in Operation opt) { }
    }

    public abstract class ActorBase<ACTOR, PROPERTY, SKILL, BUFF> : ActorBase
        where ACTOR : ActorBase
        where PROPERTY : PropertyBase
        where SKILL : SkillBase<ACTOR, BUFF>
        where BUFF : BuffBase<ACTOR>
    {
        public PROPERTY Property { get; set; }
        public List<SKILL> Skills { get; set; } = new();
        public List<BUFF> Buffs { get; set; } = new();

        public override void OnUpdate()
        {
            for (int i = 0; i < Skills.Count; i++)
            {
                Skills[i].Update();
            }
            for (int i = 0; i < Buffs.Count; i++)
            {
                if (!Buffs[i].OnUpdate())
                {
                    Buffs.RemoveAt(i);
                    if (i >= 0) i--;
                }
            }
        }

        public void AddSkill(SKILL skill)
        {
            skill.Self = this as ACTOR;
            Skills.Add(skill);
        }

        public virtual void UseSkill(int index)
        {
            if (index < 0 || index >= Skills.Count)
                return;
            Skills[index].UseSkill();
        }

        public virtual void Damage(ACTOR target, BUFF buff)
        {
            if (Property.IsDeath)
                return;
            buff.Self = target;
            buff.Target = this as ACTOR;
            buff.OnTrigger();
            OnDamage(target);
            if (Property.IsDeath)
            {
                OnDeath(target);
                var actor = target as ActorBase<ACTOR, PROPERTY, SKILL, BUFF>;
                actor.OnGetExp(this as ACTOR);
            }
        }

        public virtual void OnDamage(ACTOR target)
        {
        }

        public virtual void OnDeath(ACTOR target)
        {
        }

        public virtual void OnGetExp(ACTOR target)
        {
        }
    }
}